home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CICA 1995 August
/
CICA - The Ultimate Collection of Shareware for Windows (Disc 2) (August 1995).iso
/
disc2
/
nt
/
source.exe
/
POSIX
/
ELVIS
/
CURSES.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-06
|
16KB
|
770 lines
/* curses.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the functions & variables needed for a tiny subset of
* curses. The principle advantage of this version of curses is its
* extreme speed. Disadvantages are potentially larger code, few supported
* functions, limited compatibility with full curses, and only stdscr.
*/
#include "config.h"
#include "vi.h"
#if ANY_UNIX
# if UNIXV
# include <termio.h>
# undef TIOCWINSZ /* we can't handle it correctly yet */
# else
# include <sgtty.h>
# endif
#elif DF_POSIX
# include <termios.h>
#endif
#if TOS
# include <osbind.h>
#endif
#if OSK
# include <sgstat.h>
#endif
#include <signal.h>
extern char *getenv(const char *);
static void starttcap();
/* variables, publicly available & used in the macros */
short ospeed; /* speed of the tty, eg B2400 */
#if OSK
char PC_; /* Pad char */
char *BC; /* backspace character string */
#else
char PC; /* Pad char */
#endif
WINDOW *stdscr; /* pointer into kbuf[] */
WINDOW kbuf[KBSIZ]; /* a very large output buffer */
int LINES; /* :li#: number of rows */
int COLS; /* :co#: number of columns */
int AM; /* :am: boolean: auto margins? */
int PT; /* :pt: boolean: physical tabs? */
char *VB; /* :vb=: visible bell */
char *UP; /* :up=: move cursor up */
char *SO; /* :so=: standout start */
char *SE; /* :se=: standout end */
char *US = ""; /* :us=: underline start */
char *UE = ""; /* :ue=: underline end */
char *MD = ""; /* :md=: bold start */
char *ME = ""; /* :me=: bold end */
char *AS; /* :as=: alternate (italic) start */
char *AE; /* :ae=: alternate (italic) end */
char *CM; /* :cm=: cursor movement */
char *CE; /* :ce=: clear to end of line */
char *CD; /* :cd=: clear to end of screen */
char *AL; /* :al=: add a line */
char *DL; /* :dl=: delete a line */
#if OSK
char *SR_; /* :sr=: scroll reverse */
#else
char *SR; /* :sr=: scroll reverse */
#endif
char *KS; /* :ks=: init string for cursor */
char *KE; /* :ke=: restore string for cursor */
char *KU; /* :ku=: key sequence sent by up arrow */
char *KD; /* :kd=: key sequence sent by down arrow */
char *KL; /* :kl=: key sequence sent by left arrow */
char *KR; /* :kr=: key sequence sent by right arrow */
char *HM; /* :HM=: key sequence sent by the <Home> key */
char *EN; /* :EN=: key sequence sent by the <End> key */
char *PU; /* :PU=: key sequence sent by the <PgUp> key */
char *PD; /* :PD=: key sequence sent by the <PgDn> key */
char *IM; /* :im=: insert mode start */
char *IC = ""; /* :ic=: insert the following character */
char *EI; /* :ei=: insert mode end */
char *DC; /* :dc=: delete a character */
char *TI; /* :ti=: terminal init */ /* GB */
char *TE; /* :te=: terminal exit */ /* GB */
#ifndef NO_CURSORSHAPE
char *CQ = (char *)0;/* :cQ=: normal cursor */
char *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
char *CV = (char *)2;/* :cV=: cursor used for VI command mode */
char *CI = (char *)3;/* :cI=: cursor used for VI input mode */
char *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
#endif
char *aend = ""; /* end an attribute -- either UE or ME */
char ERASEKEY; /* backspace key taken from ioctl structure */
#if ANY_UNIX
# if UNIXV
static struct termio oldtermio; /* original tty mode */
static struct termio newtermio; /* cbreak/noecho tty mode */
# else
static struct sgttyb oldsgttyb; /* original tty mode */
static struct sgttyb newsgttyb; /* cbreak/nl/noecho tty mode */
static int oldint; /* ^C or DEL, the "intr" character */
# ifdef TIOCSLTC
static int oldswitch; /* ^Z, the "suspend" character */
static int oldquote; /* ^V, the "quote next char" char */
# endif
# endif
#elif DF_POSIX
struct termios oldtermio; /* original tty mode */
struct termios newtermio; /* cbreak/noecho tty mode */
#endif
#if OSK
static struct sgbuf oldsgttyb; /* orginal tty mode */
static struct sgbuf newsgttyb; /* noecho tty mode */
#endif
static char *capbuf; /* capability string buffer */
void initscr()
{
/* make sure TERM variable is set */
#if MSDOS
char *val;
if (! (val = getenv("TERM"))
|| !strcmp(val, "pcbios"))
#else
if (!getenv("TERM"))
#endif
{
#if ANY_UNIX || DF_POSIX
write(2, "Environment variable TERM must be set\n", (unsigned)38);
exit(1);
#endif
#if OSK
writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
exit(1);
#endif
#if MSDOS || TOS
getsize(0);
#endif
}
else
{
#if MSDOS
*o_pcbios=0;
#endif
/* start termcap stuff */
starttcap();
}
/* create stdscr and curscr */
stdscr = kbuf;
/* change the terminal mode to cbreak/noecho */
#if ANY_UNIX
# if UNIXV
ioctl(2, TCGETA, &oldtermio);
# else
ioctl(2, TIOCGETP, &oldsgttyb);
# endif
#elif DF_POSIX
if (tcgetattr(2, &oldtermio) < 0 )
perror("Could not get tty attributes");
// if (oldtermio.c_lflag & ICANON)
// printf("icanon\n");
// if (oldtermio.c_lflag & ECHO)
// printf("echo\n");
#endif
#if OSK
_gs_opt(0, &oldsgttyb);
#endif
resume_curses(TRUE);
}
void endwin()
{
/* change the terminal mode back the way it was */
suspend_curses();
}
static int curses_active = FALSE;
void suspend_curses()
{
#if ANY_UNIX && !UNIXV
struct tchars tbuf;
# ifdef TIOCSLTC
struct ltchars ltbuf;
# endif
#endif
#ifndef NO_CURSORSHAPE
if (has_CQ)
{
do_CQ();
}
#endif
if (has_TE) /* GB */
{
do_TE();
}
if (has_KE)
{
do_KE();
}
refresh();
/* change the terminal mode back the way it was */
#if ANY_UNIX
# if UNIXV
ioctl(2, TCSETAW, &oldtermio);
# else
ioctl(2, TIOCSETP, &oldsgttyb);
ioctl(2, TIOCGETC, &tbuf);
tbuf.t_intrc = oldint;
ioctl(2, TIOCSETC, &tbuf);
# ifdef TIOCSLTC
ioctl(2, TIOCGLTC, <buf);
ltbuf.t_suspc = oldswitch;
ltbuf.t_lnextc = oldquote;
ioctl(2, TIOCSLTC, <buf);
# endif
# endif
# elif DF_POSIX
if (tcsetattr(2, TCSANOW, &oldtermio))
perror("Could not set old tty attributes");
#endif
#if OSK
_ss_opt(0, &oldsgttyb);
#endif
curses_active = FALSE;
}
void resume_curses(quietly)
int quietly;
{
if (!curses_active)
{
/* change the terminal mode to cbreak/noecho */
#if ANY_UNIX
# if UNIXV
ospeed = (oldtermio.c_cflag & CBAUD);
ERASEKEY = oldtermio.c_cc[VERASE];
newtermio = oldtermio;
newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
newtermio.c_oflag &= ~OPOST;
newtermio.c_lflag &= ISIG;
newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
newtermio.c_cc[VMIN] = 1;
newtermio.c_cc[VTIME] = 0;
# ifdef VSWTCH
newtermio.c_cc[VSWTCH] = 0;
# endif
ioctl(2, TCSETAW, &newtermio);
# else /* BSD or V7 or Coherent or Minix */
struct tchars tbuf;
# ifdef TIOCSLTC
struct ltchars ltbuf;
# endif
ospeed = oldsgttyb.sg_ospeed;
ERASEKEY = oldsgttyb.sg_erase;
newsgttyb = oldsgttyb;
newsgttyb.sg_flags |= CBREAK;
newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
ioctl(2, TIOCSETP, &newsgttyb);
ioctl(2, TIOCGETC, &tbuf);
oldint = tbuf.t_intrc;
tbuf.t_intrc = ctrl('C'); /* always use ^C for interrupts */
ioctl(2, TIOCSETC, &tbuf);
# ifdef TIOCSLTC
ioctl(2, TIOCGLTC, <buf);
oldswitch = ltbuf.t_suspc;
ltbuf.t_suspc = 0; /* disable ^Z for elvis */
oldquote = ltbuf.t_lnextc;
ltbuf.t_lnextc = 0; /* disable ^V for elvis */
ioctl(2, TIOCSLTC, <buf);
# endif
# endif
#elif DF_POSIX
ospeed = cfgetospeed(&oldtermio);
ERASEKEY = oldtermio.c_cc[VERASE];
newtermio = oldtermio;
//printf("Soldtermio = %x \n", oldtermio.c_lflag);
newtermio.c_iflag |= (IXON|IXOFF|ISTRIP|IGNBRK);
newtermio.c_oflag &= ~OPOST;
newtermio.c_lflag &= (~ISIG);
//newtermio.c_lflag |= ISIG;
newtermio.c_lflag &= (~ICANON & ~ECHO);
//printf("Snewtermio = %x \n", newtermio.c_lflag);
newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
//printf("curses.c: setting attr %x \n", newtermio.c_lflag);
//printf("curses.c: old attr %x \n", oldtermio.c_lflag);
strcpy(newtermio.c_cc, "TEST");
if (tcsetattr(2, TCSANOW, &newtermio))
perror("Could not set new tty attributes");
#endif
#
#if OSK
newsgttyb = oldsgttyb;
newsgttyb.sg_echo = 0;
newsgttyb.sg_eofch = 0;
newsgttyb.sg_kbach = 0;
newsgttyb.sg_kbich = ctrl('C');
_ss_opt(0, &newsgttyb);
ospeed = oldsgttyb.sg_baud;
ERASEKEY = oldsgttyb.sg_bspch;
#endif
if (has_TI) /* GB */
{
do_TI();
}
if (has_KS)
{
do_KS();
}
curses_active = TRUE;
}
/* If we're supposed to quit quietly, then we're done */
if (quietly)
{
return;
}
signal(SIGINT, SIG_IGN);
move(LINES - 1, 0);
do_SO();
qaddstr("[Press <RETURN> to continue]");
do_SE();
refresh();
ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
if (kbuf[0] == ':')
{
mode = MODE_COLON;
addch('\n');
refresh();
}
else
{
mode = MODE_VI;
redraw(MARK_UNSET, FALSE);
}
exwrote = FALSE;
#if TURBOC
signal(SIGINT, (void(*)()) trapint);
#else
signal(SIGINT, trapint);
#endif
}
static void lacking(s)
char *s;
{
write(2, "This termcap entry lacks the :", (unsigned)30);
write(2, s, (unsigned)2);
write(2, "=: capability\n", (unsigned)14);
#if OSK
write(2, "\l", 1);
#endif
exit(1);
}
static void starttcap()
{
char *str;
static char cbmem[800];
#define MUSTHAVE(T,s) if (!(T = tgetstr(s, &capbuf))) lacking(s)
#define MAYHAVE(T,s) if (str = tgetstr(s, &capbuf)) T = str
#define PAIR(T,U,sT,sU) T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
/* allocate memory for capbuf */
capbuf = cbmem;
/* get the termcap entry */
switch (tgetent(kbuf, getenv("TERM")))
{
case -1:
write(2, "Can't read /etc/termcap\n", (unsigned)24);
#if OSK
write(2, "\l", 1);
#endif
exit(2);
case 0:
write(2, "Unrecognized TERM type\n", (unsigned)23);
#if OSK
write(2, "\l", 1);
#endif
exit(3);
}
#if 0
puts(kbuf);
sleep(3);
#endif
/* get strings */
MUSTHAVE(UP, "up");
MAYHAVE(VB, "vb");
MUSTHAVE(CM, "cm");
PAIR(SO, SE, "so", "se");
PAIR(TI, TE, "ti", "te");
if (tgetnum("ug") <= 0)
{
PAIR(US, UE, "us", "ue");
PAIR(MD, ME, "md", "me");
/* get italics, or have it default to underline */
PAIR(AS, AE, "as", "ae");
if (!*AS)
{
AS = US;
AE = UE;
}
}
MAYHAVE(AL, "al");
MAYHAVE(DL, "dl");
MUSTHAVE(CE, "ce");
MAYHAVE(CD, "cd");
#if OSK
MAYHAVE(SR_, "sr");
#else
MAYHAVE(SR, "sr");
#endif
PAIR(IM, EI, "im", "ei");
MAYHAVE(IC, "ic");
MAYHAVE(DC, "dc");
/* other termcap stuff */
AM = tgetflag("am");
PT = tgetflag("pt");
getsize(0);
/* Key sequences */
PAIR(KS, KE, "ks", "ke");
MAYHAVE(KU, "ku"); /* up */
MAYHAVE(KD, "kd"); /* down */
MAYHAVE(KL, "kl"); /* left */
MAYHAVE(KR, "kr"); /* right */
MAYHAVE(PU, "kP"); /* PgUp */
MAYHAVE(PD, "kN"); /* PgDn */
MAYHAVE(HM, "kh"); /* Home */
MAYHAVE(EN, "kH"); /* End */
#ifndef CRUNCH
if (!PU) MAYHAVE(PU, "K2"); /* "3x3 pad" names for PgUp, etc. */
if (!PD) MAYHAVE(PD, "K5");
if (!HM) MAYHAVE(HM, "K1");
if (!EN) MAYHAVE(EN, "K4");
MAYHAVE(PU, "PU"); /* old XENIX names for PgUp, etc. */
MAYHAVE(PD, "PD"); /* (overrides others, if used.) */
MAYHAVE(HM, "HM");
MAYHAVE(EN, "EN");
#endif
#ifndef NO_CURSORSHAPE
/* cursor shapes */
CQ = tgetstr("cQ", &capbuf);
if (has_CQ)
{
CX = tgetstr("cX", &capbuf);
if (!CX) CX = CQ;
CV = tgetstr("cV", &capbuf);
if (!CV) CV = CQ;
CI = tgetstr("cI", &capbuf);
if (!CI) CI = CQ;
CR = tgetstr("cR", &capbuf);
if (!CR) CR = CQ;
}
# ifndef CRUNCH
else
{
PAIR(CQ, CV, "ve", "vs");
CX = CI = CR = CQ;
}
# endif /* !CRUNCH */
#endif /* !NO_CURSORSHAPE */
#undef MUSTHAVE
#undef MAYHAVE
#undef PAIR
}
/* This function gets the window size. It uses the TIOCGWINSZ ioctl call if
* your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
* This function is called once during initialization, and thereafter it is
* called whenever the SIGWINCH signal is sent to this process.
*/
int getsize(signo)
int signo;
{
int lines;
int cols;
#ifdef TIOCGWINSZ
struct winsize size;
#endif
#ifdef SIGWINCH
/* reset the signal vector */
signal(SIGWINCH, getsize);
#endif
/* get the window size, one way or another. */
lines = cols = 0;
#ifdef TIOCGWINSZ
if (ioctl(2, TIOCGWINSZ, &size) >= 0)
{
lines = size.ws_row;
cols = size.ws_col;
}
#endif
if ((lines == 0 || cols == 0) && signo == 0)
{
LINES = CHECKBIOS(v_rows(), tgetnum("li"));
COLS = CHECKBIOS(v_cols(), tgetnum("co"));
}
if (lines >= 2 && cols >= 30)
{
LINES = lines;
COLS = cols;
}
/* Make sure we got values that we can live with */
if (LINES < 2 || COLS < 30)
{
write(2, "Screen too small\n", (unsigned)17);
#if OSK
write(2, "\l", 1);
#endif
endwin();
exit(2);
}
/* !!! copy the new values into Elvis' options */
{
extern char o_columns[], o_lines[];
*o_columns = COLS;
*o_lines = LINES;
}
return 0;
}
/* This is a function version of addch() -- it is used by tputs() */
int faddch(ch)
int ch;
{
addch(ch);
return 0;
}
/* These functions are equivelent to the macros of the same names... */
void qaddstr(str)
char *str;
{
REG char *s_, *d_;
#if MSDOS
if (o_pcbios[0])
{
while (*str)
qaddch(*str++);
return;
}
#endif
for (s_=(str), d_=stdscr; *d_++ = *s_++; )
{
}
stdscr = d_ - 1;
}
void attrset(a)
int a;
{
do_aend();
if (a == A_BOLD)
{
do_MD();
aend = ME;
}
else if (a == A_UNDERLINE)
{
do_US();
aend = UE;
}
else if (a == A_ALTCHARSET)
{
do_AS();
aend = AE;
}
else
{
aend = "";
}
}
void insch(ch)
int ch;
{
if (has_IM)
do_IM();
do_IC();
qaddch(ch);
if (has_EI)
do_EI();
}
#if MSDOS
static int alarmtime;
/* raw read - #defined to read (0, ...) on non-MSDOS.
* With MSDOS, am maximum of 1 byte is read.
* If more bytes should be read, just change the loop.
* The following code uses the IBM-PC-System-Timer, so probably wont't work
* on non-compatibles.
*/
/*ARGSUSED*/
ttyread(buf, len)
char *buf;
int len;
{
volatile char far *biostimer;
char oldtime;
int nticks = 0;
int pos = 0;
biostimer = (char far *)0x0040006cl;
oldtime = *biostimer;
while (!pos && (!alarmtime || nticks<alarmtime))
{ if (kbhit())
if ((buf[pos++] = getch()) == 0) /* function key */
buf[pos-1] = '#';
if (oldtime != *biostimer)
{ nticks++;
oldtime = *biostimer;
}
}
return pos;
}
alarm(time)
int time;
{
alarmtime = 2 * time; /* ticks are 1/18 sec. */
}
sleep(seconds)
unsigned seconds;
{
volatile char far *biostimer = (char far *)0x0040006cl;
char stop;
stop = *biostimer + 18 * seconds;
while (*biostimer != stop)
{
}
}
#endif
#if TOS
static int alarmtime;
static long timer;
static gettime()
{
timer = *(long *)(0x4ba);
}
/*ARGSUSED*/
ttyread(buf, len)
char *buf;
int len;
{
int pos=0;
long l;
long endtime;
Supexec(gettime);
endtime = timer+alarmtime;
while (!pos && (!alarmtime || timer<endtime))
{
if (Bconstat(2))
{
l = Bconin(2);
if ((buf[pos++]=l) == '\0')
{
buf[pos-1]='#';
buf[pos++]=l>>16;
}
}
Supexec(gettime);
}
return pos;
}
alarm(time)
int time;
{
alarmtime = 50 * time; /* ticks are 1/200 sec. */
}
ttywrite(buf, len)
char *buf;
int len;
{
while (len--)
Bconout(2, *buf++);
}
#endif
#if OSK
ttyread(buf, len)
char *buf;
int len;
{
REG int i;
if ((i = _gs_rdy(0)) > 0)
return read(0, buf, i < len ? i : len);
else
return read(0, buf, 1);
}
alarm(time)
int time;
{
#define TIME(secs) ((secs << 8) | 0x80000000)
static int alrmid;
if (time)
alrmid = alm_set(SIGQUIT, TIME(time));
else
alm_delete(alrmid);
}
#endif /* OSK */